home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tech Arsenal 1
/
Tech Arsenal (Arsenal Computer).ISO
/
tek-04
/
adatimer.zip
/
TIMEL2.ADA
< prev
next >
Wrap
Text File
|
1990-06-07
|
7KB
|
231 lines
-- Listing 2. An implementation dependent package body.
with PORT, BIT_OPS;
package body POLLED_TIMER is
TIMER_TICK : float := 1.0 / 1_193_180.0;
TIMER_MAX : float := 65_536.0 * TIMER_TICK;
type Words is range 0 .. 65_535;
for Words'SIZE use 32;
TIMER_PERIOD : Words;
LOW_BYTE : integer;
HIGH_BYTE : integer;
TIMER_MODE : Modes;
-- IBM PC physical addresses.
TIMER_BASE_ADDRESS : constant
:= 16#40#;
TIMER_2_REGISTER : constant
:= TIMER_BASE_ADDRESS + 2;
TIMER_CONTROL : constant
:= TIMER_BASE_ADDRESS + 3;
SPEAKER_CONTROL : constant
:= 16#61#;
-- IBM PC physical constants.
TIMER_2_GATE : constant
:= 2#0000_0001#;
SPEAKER_ENABLE : constant
:= 2#0000_0010#;
-- Intel 8254 constants
-- (See Intel 8254 data sheet.)
TIMER_2_MODE_0 : constant
:= 2#10_11_000_0#;
READBACK_TIMER_2_STATUS : constant
:= 2#11_10_100_0#;
TIMER_2_READ_COUNT : constant
:= 2#11_01_100_0#;
OUTPUT_FLAG : constant
:= 2#1000_0000#;
NOT_FINISHED : constant
:= 0;
-- Temporary variable (made global
-- to avoid frequent elaboration).
STATUS : integer;
function Make_Word(HIGH_BYTE, LOW_BYTE : integer)
return Words is
WORD, HIGH, LOW : Words;
begin
HIGH := 256 * Words(HIGH_BYTE);
LOW := Words(LOW_BYTE);
WORD := HIGH + LOW;
return WORD;
end Make_Word;
function Lsb(WORD : Words) return integer is
LOW : integer;
begin
LOW := integer(WORD mod 256);
return LOW;
end Lsb;
function Msb(WORD : Words) return integer is
HIGH : integer;
begin
HIGH := integer(WORD / 256);
return HIGH;
end Msb;
-- The following is a Meridian 4.0 bug work-around.
-- Meridian computes float(WORD) = negative when
-- WORD is of type Words and greater than 32,767.
function To_Float(WORD : Words) return float is
HIGH, LOW : float;
begin
HIGH := float(Msb(WORD));
LOW := float(Lsb(WORD));
return 256.0 * HIGH + LOW;
end To_Float;
procedure Set(PERIOD : Seconds;
MODE : Modes) is
begin
-- Check for range errors.
if Dimensionless(PERIOD) > TIMER_MAX then
raise INVALID_PERIOD;
end if;
if Dimensionless(PERIOD) < TIMER_TICK then
raise INVALID_PERIOD;
end if;
-- Make sure the timer is stopped.
Stop;
-- Convert seconds into clock ticks.
TIMER_PERIOD := Words(Dimensionless(PERIOD)
/TIMER_TICK);
-- Load the clock ticks into the timer.
LOW_BYTE := Lsb(TIMER_PERIOD);
HIGH_BYTE := Msb(TIMER_PERIOD);
PORT.Out_Byte(TIMER_2_REGISTER,LOW_BYTE);
PORT.Out_Byte(TIMER_2_REGISTER,HIGH_BYTE);
-- Set the mode (single or repreated).
TIMER_MODE := MODE;
end Set;
procedure Start is
use BIT_OPS; -- for "or" (bit set)
begin
-- Get current status.
STATUS := PORT.In_Byte(SPEAKER_CONTROL);
-- Set Timer 2 gate without affecting other control
-- bits.
STATUS := STATUS or TIMER_2_GATE;
-- Put modified status.
PORT.Out_Byte(SPEAKER_CONTROL,STATUS);
end Start;
procedure Restart is
use BIT_OPS; -- for "or" (bit set)
begin
-- Load the clock ticks into the timer.
PORT.Out_Byte(TIMER_2_REGISTER,LOW_BYTE);
PORT.Out_Byte(TIMER_2_REGISTER,HIGH_BYTE);
-- Start the timer.
Start;
end Restart;
function Has_Expired return boolean is
use BIT_OPS; -- for "and"
begin
-- Latch status.
PORT.Out_Byte(TIMER_CONTROL,READBACK_TIMER_2_STATUS);
STATUS := Port.In_Byte(TIMER_2_REGISTER);
if (STATUS and OUTPUT_FLAG) = NOT_FINISHED then
return FALSE;
else
case TIMER_MODE is
when SINGLE =>
return TRUE;
when REPEATED =>
Restart;
return TRUE;
end case;
end if;
end Has_Expired;
procedure Stop is
use BIT_OPS; -- for "and" and "not" (bit clear)
begin
-- Get current status.
STATUS := PORT.In_Byte(SPEAKER_CONTROL);
-- Clear Timer 2 gate without affecting other control
-- bits.
STATUS := STATUS and not TIMER_2_GATE;
-- Put modified status.
PORT.Out_Byte(SPEAKER_CONTROL,STATUS);
end Stop;
function Time_Used return Seconds is
MSB, LSB : integer;
CURRENT_VALUE, DIFFERENCE : Words;
TIME : float;
begin
-- Latch the current count (without stopping
-- the timer).
PORT.Out_Byte(TIMER_CONTROL,TIMER_2_READ_COUNT);
LSB := PORT.In_Byte(TIMER_2_REGISTER);
MSB := PORT.In_Byte(TIMER_2_REGISTER);
CURRENT_VALUE := Make_Word(MSB,LSB);
DIFFERENCE := TIMER_PERIOD - CURRENT_VALUE;
-- Meridian 4.0 incorrectly computes the next line.
-- TIME := float(DIFFERENCE) * TIMER_TICK;
TIME := To_Float(DIFFERENCE) * TIMER_TICK;
return Type_Convert(TIME);
end Time_Used;
function Time_Left return Seconds is
MSB, LSB : integer;
CURRENT_VALUE : Words;
TIME : float;
begin
-- Latch the current count (without stopping
-- the timer).
PORT.Out_Byte(TIMER_CONTROL,TIMER_2_READ_COUNT);
LSB := PORT.In_Byte(TIMER_2_REGISTER);
MSB := PORT.In_Byte(TIMER_2_REGISTER);
CURRENT_VALUE := Make_Word(MSB,LSB);
-- Meridian 4.0 incorrectly computes the next line.
-- TIME := float(CURRENT_VALUE) * TIMER_TICK;
TIME := To_Float(CURRENT_VALUE) * TIMER_TICK;
return Type_Convert(TIME);
end Time_Left;
function Max_Period return Seconds is
begin
return Type_Convert(TIMER_MAX);
end Max_Period;
function Single_Tick return Seconds is
begin
return Type_Convert(TIMER_TICK);
end Single_Tick;
-- This package uses Timer 2, which is
-- usually used to beep the speaker.
-- This procedure disables the speaker.
procedure Turn_Off_Speaker is
use BIT_OPS; -- for "and" (bit clear)
begin
-- Get current status.
STATUS := PORT.In_Byte(SPEAKER_CONTROL);
-- Clear SPEAKER_ENABLE bit without affecting
-- other control bits.
STATUS := STATUS and not SPEAKER_ENABLE;
-- Put modified status.
PORT.Out_Byte(SPEAKER_CONTROL,STATUS);
end Turn_Off_Speaker;
procedure Initialize_Timer_2 is
begin
PORT.Out_Byte(TIMER_CONTROL,TIMER_2_MODE_0);
end Initialize_Timer_2;
begin
Turn_Off_Speaker; -- so we won't hear the timer!
Initialize_Timer_2;
end POLLED_TIMER;